var __createBinding =
    (this && this.__createBinding) ||
    (Object.create
        ? (o, m, k, k2) => {
              if (k2 === undefined) k2 = k;
              var desc = Object.getOwnPropertyDescriptor(m, k);
              if (
                  !desc ||
                  ("get" in desc
                      ? !m.__esModule
                      : desc.writable || desc.configurable)
              ) {
                  desc = { enumerable: true, get: () => m[k] };
              }
              Object.defineProperty(o, k2, desc);
          }
        : (o, m, k, k2) => {
              if (k2 === undefined) k2 = k;
              o[k2] = m[k];
          });
var __setModuleDefault =
    (this && this.__setModuleDefault) ||
    (Object.create
        ? (o, v) => {
              Object.defineProperty(o, "default", {
                  enumerable: true,
                  value: v,
              });
          }
        : (o, v) => {
              o.default = v;
          });
var __importStar =
    (this && this.__importStar) ||
    ((mod) => {
        if (mod?.__esModule) return mod;
        var result = {};
        if (mod != null)
            for (var k in mod)
                if (k !== "default" && Object.hasOwn(mod, k))
                    __createBinding(result, mod, k);
        __setModuleDefault(result, mod);
        return result;
    });
var __importDefault =
    (this && this.__importDefault) ||
    ((mod) => (mod?.__esModule ? mod : { default: mod }));
Object.defineProperty(exports, "__esModule", { value: true });
exports.ReassignmentRemover = void 0;
const t = __importStar(require("@babel/types"));
const transformation_1 = require("../transformation");
const variable_1 = require("../../helpers/variable");
const traverse_1 = __importDefault(require("@babel/traverse"));
class ReassignmentRemover extends transformation_1.Transformation {
    /**
     * Executes the transformation.
     * @param log The log function.
     */
    execute(_log) {
        const self = this;
        (0, traverse_1.default)(this.ast, {
            enter(path) {
                const variable = (0, variable_1.findConstantVariable)(
                    path,
                    t.isIdentifier,
                );
                if (!variable || variable.name === variable.expression.name) {
                    return;
                }
                for (const referencePath of variable.binding.referencePaths) {
                    referencePath.replaceWith(
                        t.identifier(variable.expression.name),
                    );
                    self.setChanged();
                }
                // remove any declarations of variable we are replacing
                for (const declarationPath of [
                    ...variable.binding.constantViolations,
                    variable.binding.path,
                ]) {
                    if (declarationPath !== path) {
                        declarationPath.remove();
                    }
                }
                if (
                    path.isStatement() ||
                    path.isVariableDeclarator() ||
                    path.parentPath?.isStatement()
                ) {
                    path.remove();
                } else {
                    // might have side effects, replace with RHS instead
                    path.replaceWith(variable.expression);
                }
            },
        });
        return this.hasChanged();
    }
}
exports.ReassignmentRemover = ReassignmentRemover;
ReassignmentRemover.properties = {
    key: "reassignmentRemoval",
    rebuildScopeTree: true,
};
